package com.msb.mall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.msb.common.dto.SkuHasStockDto;
import com.msb.common.exception.NoStockException;
import com.msb.common.utils.PageUtils;
import com.msb.common.utils.Query;
import com.msb.common.utils.R;
import com.msb.mall.ware.dao.WareSkuDao;
import com.msb.mall.ware.entity.WareSkuEntity;
import com.msb.mall.ware.feign.ProductFeignService;
import com.msb.mall.ware.service.WareSkuService;
import com.msb.mall.ware.vo.OrderItemVo;
import com.msb.mall.ware.vo.WareSkuLockVo;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    WareSkuDao wareSkuDao;
    @Autowired
    ProductFeignService productFeignService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if(StringUtils.isNotEmpty(skuId)){
            wrapper.eq("sku_id",skuId);
        }
        String wareId = (String) params.get("wareId");
        if(StringUtils.isNotEmpty(wareId)){
            wrapper.eq("ware_id",wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    /**
     * 入库操作
     * @param skuId 商品编号
     * @param wareId 仓库编号
     * @param skuNum 商品数量
     */
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //1.判断是否有该商品和仓库的入库记录
        List<WareSkuEntity> list = this.list(new QueryWrapper<WareSkuEntity>()
                .eq("sku_id", skuId)
                .eq("ware_id", wareId)
        );
        if(list == null || list.isEmpty()){
            //没有就新增商品库存记录
            WareSkuEntity wareSku = new WareSkuEntity();
            wareSku.setWareId(wareId);
            wareSku.setSkuId(skuId);
            wareSku.setStock(skuNum);
            wareSku.setStockLocked(0);
            //设置名称
            //通过feign 远程调用
            try {
                R r = productFeignService.productInfo(skuId);
                if(r.getCode() == 0){
                    Map<String,Object> skuInfo = (Map<String, Object>) r.get("skuInfo");
                    wareSku.setSkuName(skuInfo.get("skuName").toString());
                }else{
                    log.error("调用Product服务处理，获取sku信息操作失败......");
                    throw new RuntimeException();
                }
            }catch (Exception e){
                log.error("调用Product服务处理，获取sku信息操作失败......");
                throw new RuntimeException();
            }
            this.save(wareSku);
        }else{
            //如果有就更新
            wareSkuDao.addStock(skuId, wareId, skuNum);
        }
    }

    /**
     * 获取每个skuId的库存
     * @param skuIds skuId
     * @return 库存信息
     */
    @Override
    public List<SkuHasStockDto> getSkuHasStock(List<Long> skuIds) {
        return skuIds.stream().map(skuId ->{
            Long count = wareSkuDao.getSkuStock(skuId);
            SkuHasStockDto dto = new SkuHasStockDto();
            dto.setSkuId(skuId);
            dto.setHasStock(count > 0);
            return dto;
        }).collect(Collectors.toList());
    }

    /**
     * 锁定库存操作
     * @param vo
     * @return
     */
    @Transactional
    @Override
    public Boolean orderLockStock(WareSkuLockVo vo) {
        List<OrderItemVo> items = vo.getItems();
        //找到具有库存的仓库
        List<SkuWareHasLock> wareHasLocks = items.stream().map(item -> {
            SkuWareHasLock skuWareHasLock = new SkuWareHasLock();
            List<WareSkuEntity> wareSkus = this.baseMapper.listHasStock(item.getSkuId());
            skuWareHasLock.setWareSkus(wareSkus);
            skuWareHasLock.setNum(item.getCount());
            return skuWareHasLock;
        }).collect(Collectors.toList());
        //锁定库存
        for (SkuWareHasLock skuWareHasLock :wareHasLocks) {
            Long skuId = skuWareHasLock.getSkuId();
            List<WareSkuEntity> wareIds = skuWareHasLock.getWareSkus();
            if(wareIds == null || wareIds.isEmpty()){
                //当前没有库存了
                throw new NoStockException(skuId);
            }
            //当前需要锁定的商品库存
            Integer count = skuWareHasLock.getNum();
            //表示当前的skuId 没有锁定完成
            boolean skuStocked = false;
            for (WareSkuEntity wareSku : wareIds) {
                //循环获取到对应的 仓库 需要锁定库存

                //获取当前仓库能够锁定的库存数
                Integer canStock = wareSku.getStock() - wareSku.getStockLocked();
                if(count <= canStock){
                    //表示当前skuId 的商品数量小于等于需要锁定的库存
                    Integer i = this.baseMapper.lockSkuStock(skuId,wareSku.getWareId(),count);
                    count = 0;
                    skuStocked = true;
                }else{
                    //需要锁定的库存大于 可以锁定的库存 按照已有的数量来锁定
                    Integer i = this.baseMapper.lockSkuStock(skuId,wareSku.getWareId(),canStock);
                    count = count - canStock;
                }
                if(count <= 0 ){
                    //表示所有商品都锁定了
                    break;
                }
            }
            if(count > 0){
                //说明库存没有锁定完
                throw new NoStockException(skuId);
            }
            if(!skuStocked){
                //表示上一个商品没有锁定库存功能
                throw new NoStockException(skuId);
            }
        }

        return true;
    }
    @Data
    static class SkuWareHasLock{
        private Long skuId;
        private Integer num;
        private List<WareSkuEntity> wareSkus;
    }

}
